import { EditMode } from './EditMode'
import { EntryRefactor } from './EntryRefactor'
class EditModeEntry extends EditMode {
  initCssStyles () {
    this.setCssStyle('article-editing-area', 'user-select', 'none')
    this.addCssStyle('.w', '{padding: 0.5em 0em;}')
    this.addCssStyle(
      '.w-content.selected',
      '{background-color: rgba(14, 68, 247, 0.1);}'
    )
    this.addCssStyle(
      '.w.selected-start::before',
      '{content: "";padding: 0px 0px 0px 3px;margin: 0px 0px 0px 2px;background-color: rgba(14, 68, 247, 0.1);border-left: 1px solid rgba(76, 121, 245);border-top: 1px solid rgba(76, 121, 245);border-bottom: 1px solid rgba(76, 121, 245);}'
    )
    this.addCssStyle(
      '.w.selected-end::after',
      '{content: "";padding: 0px 0px 0px 3px;margin: 0px 2px 0px 0px;background-color: rgba(14, 68, 247, 0.1);border-right: 1px solid rgba(76, 121, 245);border-top: 1px solid rgba(76, 121, 245);border-bottom: 1px solid rgba(76, 121, 245);}'
    )
    this.addCssStyle('.entry.selected', '{color: rgb(251, 193, 5);}')
    this.addCssStyle('.s.entry-mode', '{cursor: pointer;}')
    this.addCssStyle('.cluster.entry-mode', '{cursor: pointer;}')
    // TODO 未来如果新增更多编辑模式, 是否有必要在ondestroy方法中将新添加的选择器删除, 以防冲突??
    let sentences = this.rootElement.getElementsByClassName('s')
    for (let i = 0; i < sentences.length; i++) {
      sentences[i].classList.add('entry-mode')
    }
    let clusters = this.rootElement.getElementsByClassName('cluster')
    for (let i = 0; i < clusters.length; i++) {
      clusters[i].classList.add('entry-mode')
    }
    // 重新划分词条使用的样式选择器
    // this.addCssStyle('.w-refactor-container', '{color: rgba(255, 255, 255, 0.6);text-shadow: 0px 0px 3px rgba(255, 255, 255, 0.6);}')
    this.addCssStyle(
      '.w-refactor',
      '{display: inline-block;margin: 0.5em 0em;}'
    )
    this.addCssStyle(
      '.w-refactor-content.selected',
      '{color: white;text-shadow: 0px 0px 3px white;}'
    )
    this.addCssStyle(
      '.spt',
      '{position: relative;cursor: pointer;padding: 9px 0px 9px 0px;}'
    )
    this.addCssStyle(
      '.spt-block-container',
      '{display: inline-block;position: relative;padding: 0 2px;}'
    )
    this.addCssStyle(
      '.spt-block.start',
      '{display: inline-block;position: relative;margin-right: 2px;width: 1px;background-color: white;box-shadow: 0px 0px 3px white;}'
    )
    this.addCssStyle(
      '.spt-block.start::before',
      '{content: "";position: absolute;top: 0;display: block;width: 3px;height: 1px;background-color: inherit;box-shadow: inherit;}'
    )
    this.addCssStyle(
      '.spt-block.start::after',
      '{content: "";position: absolute;bottom: 0;display: block;width: 3px;height: 1px;background-color: inherit;box-shadow: inherit;}'
    )
    this.addCssStyle(
      '.spt-block.end',
      '{display: inline-block;position: relative;margin-left: 2px;width: 1px;background-color: white;box-shadow: 0px 0px 3px white;}'
    )
    this.addCssStyle(
      '.spt-block.end::before',
      '{content: "";position: absolute;top: 0;right: 0;display: block;width: 3px;height: 1px;background-color: inherit;box-shadow: inherit;}'
    )
    this.addCssStyle(
      '.spt-block.end::after',
      '{content: "";position: absolute;bottom: 0;right: 0;display: block;width: 3px;height: 1px;background-color: inherit;box-shadow: inherit;}'
    )
    this.addCssStyle(
      '.spt-block.focus',
      '{background-color: #eba57d;box-shadow: 0px 0px 3px #eba57d;}'
    )
    this.addCssStyle(
      '.w-refactor-content.focus',
      '{color: #eba57d;text-shadow: 0px 0px 3px #eba57d;}'
    )
  }

  listenersDispenser (from, to) {
    from = from || this.rootElement.firstChild
    to = to || this.rootElement.lastChild
    window.onmousedown = this.listenersRegister('abandonSelected')
    EditMode.traverseSiblingElements(from, to, paragraph => {
      let sentence = paragraph.firstChild
      let idx = 0
      while (sentence) {
        sentence.ariaPosInSet = idx++
        sentence.onmouseleave = this.listenersRegister('sentenceOnMouseLeave')
        sentence.onmouseenter = this.listenersRegister('sentenceOnMouseEnter')
        sentence = sentence.nextElementSibling
      }
      return true
    })
  }

  subListenersDispenser (sentence) {
    let from = sentence.firstChild
    let to = sentence.lastChild
    let idx = 0
    EditMode.traverseSiblingElements(from, to, w => {
      w.ariaPosInSet = idx++
      switch (w.classList[0]) {
        case 'w':
          w.onmouseleave = this.listenersRegister('wordOnMouseLeave')
          w.onmouseenter = this.listenersRegister('wordOnMouseEnter')
          w.onmousedown = this.listenersRegister('wordOnMouseDown')
          break
        case 'entry':
          w.onmouseleave = this.listenersRegister('entryOnMouseLeave')
          w.onmouseenter = this.listenersRegister('entryOnMouseEnter')
          w.onmousedown = this.listenersRegister('entryOnMouseDown')
          break
      }
      return true
    })
  }

  // 放弃选中的内容
  abandonSelected (e) {
    if (!this.editing) {
      return
    }
    if (!e || e.button === 2) {
      // 右键,取消选择操作
      this.editing = false
      // 复原选中的词条的样式
      let startEl = this.startEl
      let startS = this.startS
      let endEl = this.endEl
      endEl = endEl || startEl
      EditMode.traverseSiblingElements(startEl, endEl, el => {
        // TODO 是否加入一些动画效果??
        el.firstChild.classList.remove('selected')
        return true
      })
      if (!this.mouseLeaveEndEl) {
        // 如果放弃选择,如果鼠标依然悬停在endEl,颜色不变,提高使用体验
        // 不使用刷新父元素的方法,减少性能消耗
        endEl.firstChild.classList.add('selected')
        endEl.classList.remove('selected-start', 'selected-end')
        startEl.classList.remove('selected-start', 'selected-end')
      } else {
        startS.innerHTML = startS.innerHTML
          .replace(
            /<[^<>]+? class="w-content( .+?)*?"[^<>]*?>(.+?)<\/[^<>]+?>/g,
            '$2'
          )
          .replace(/<[^<>]+? class="w( .+?)*?"[^<>]*?>(.+?)<\/[^<>]+?>/g, '$2')
      }
      this.startEl = null
      this.endEl = null
    }
  }

  sentenceOnMouseLeave (e) {
    let s = e.currentTarget
    if (this.editing && this.startS === s) {
      return
    }
    let newInnerHtml = s.innerHTML
      .replace(
        /<[^<>]+? class="w-content( .+?)*?"[^<>]*?>(.+?)<\/[^<>]+?>/g,
        '$2'
      )
      .replace(/<[^<>]+? class="w( .+?)*?"[^<>]*?>(.+?)<\/[^<>]+?>/g, '$2')
    if (s.innerHTML !== newInnerHtml) {
      s.innerHTML = newInnerHtml
    }
  }

  sentenceOnMouseEnter (e) {
    let s = e.currentTarget
    let childArr = s.childNodes
    let newInnerHtml = ''
    for (let i = 0; i < childArr.length; i++) {
      if (childArr[i].nodeType === 3) {
        newInnerHtml += childArr[i].nodeValue.replace(
          /(.)/g,
          '<span class="w"><span class="w-content">$1</span></span>'
        )
      } else {
        newInnerHtml += childArr[i].outerHTML
      }
    }
    if (s.innerHTML !== newInnerHtml) {
      s.innerHTML = newInnerHtml
    }
    this.subListenersDispenser(s)
  }

  wordOnMouseLeave (e) {
    let word = e.currentTarget
    if (!this.editing) {
      word.classList.remove('selected-start', 'selected-end')
      word.firstChild.classList.remove('selected')
      return
    }
    // 如果不在同一个句子,返回
    if (!this.startS.contains(word)) {
      return
    }
    if (this.endEl === word) {
      this.mouseLeaveEndEl = true
    }
  }

  wordOnMouseEnter (e) {
    let word = e.currentTarget
    if (!this.editing) {
      word.firstChild.classList.add('selected')
      return
    }
    // 如果不在同一个句子,返回
    if (!this.startS.contains(word)) {
      return
    }
    let startEl = this.startEl
    let endEl = this.endEl
    // 还原前一次选中的字的颜色
    EditMode.traverseSiblingElements(startEl, endEl, el => {
      if (el !== startEl) {
        el.firstChild.classList.remove('selected')
      }
      return true
    })
    // 删除起始和结束的伪类样式
    if (startEl) {
      startEl.classList.remove('selected-start', 'selected-end')
    }
    if (endEl) {
      endEl.classList.remove('selected-start', 'selected-end')
    }
    // 修改起点到终点的颜色
    let res = EditMode.traverseSiblingElements(startEl, word, el => {
      // 如果中间存在词条
      if (!el.classList.contains('w')) {
        // 回滚选中区域的样式
        EditMode.traverseSiblingElements(startEl, word, innerEl => {
          if (innerEl !== startEl && innerEl.classList.contains('w')) {
            innerEl.firstChild.classList.remove('selected')
          }
          return true
        })
        return false
      }
      el.firstChild.classList.add('selected')
      return true
    })
    // 修改起始和结束的伪类样式
    // 更新endEl
    if (!res) {
      startEl.classList.add('selected-start', 'selected-end')
    } else {
      if (parseInt(startEl.ariaPosInSet) <= parseInt(word.ariaPosInSet)) {
        startEl.classList.add('selected-start')
        word.classList.add('selected-end')
      } else {
        startEl.classList.add('selected-end')
        word.classList.add('selected-start')
      }
      this.endEl = word
      // 标记此时鼠标悬停在endEL上,这个标记在右键取消选择时使用
      this.mouseLeaveEndEl = false
    }
  }

  wordOnMouseDown (e) {
    let word = e.currentTarget
    if (e.button === 2) {
      word.firstChild.classList.add('selected')
      return
    } else if (e.button !== 0) {
      return
    }
    // 左键
    // 确定选中区起点
    if (!this.editing) {
      this.editing = true
      this.startEl = word
      this.startS = word.parentElement
      word.classList.add('selected-start', 'selected-end')
      return
    }
    // 确定选中区终点
    // 选中区存在聚簇或跨行的情况,不做处理
    if (this.endEl && this.endEl !== word) {
      return
    }
    // 整合选中的句子组成词条节点
    let newInnerHtml = ''
    let startEl = this.startEl
    let startS = this.startS
    EditMode.traverseSiblingElements(startEl, word, el => {
      newInnerHtml += el.innerHTML
      if (el !== startEl) {
        startS.removeChild(el)
      }
      return true
    })
    startEl.innerHTML = newInnerHtml
    startEl.className = 'entry'
    startEl.id = this.vueComponent.idGenerator()
    this.editing = false
    this.startEl = null
    this.endEl = null
    // 重新初始化
    this.subListenersDispenser(startS)
    if (typeof this.entryCreatedCallback === 'function') {
      this.entryCreatedCallback(
        startEl,
        startEl.id,
        this.getEntryIdx(startEl),
        this.entryEls.length
      )
    }
  }

  setEntryCreatedCallback (func) {
    this.entryCreatedCallback = func
  }

  entryOnMouseLeave (e) {
    let entry = e.currentTarget
    entry.classList.remove('selected')
  }

  entryOnMouseEnter (e) {
    if (this.editing) {
      return
    }
    let entry = e.currentTarget
    entry.classList.add('selected')
  }

  setClickEntryCallback (func) {
    this.clickEntryCallback = func
  }

  entryOnMouseDown (e) {
    if (this.editing) {
      return
    }
    let entry = e.currentTarget
    if (typeof this.clickEntryCallback === 'function') {
      this.clickEntryCallback(
        e,
        entry.id,
        this.getEntryIdx(entry),
        this.entryEls.length
      )
    }
    if (e.button !== 2) {
      return
    }
    // 右键删除词条
    // 使用文本进行替换,更新元素后,句子会再次进入onmouseenter阶段
    let s = entry.parentElement
    s.replaceChild(document.createTextNode(entry.textContent), entry)
  }

  getEntryIdx (element) {
    let entryEls =
      this.entryEls ||
      (this.entryEls = this.rootElement.getElementsByClassName('entry'))
    let targetT = element.offsetTop
    let targetL = element.offsetLeft
    let start = 0
    let end = entryEls.length - 1
    let mid = 0
    while (true) {
      let midNext = Math.ceil((start + end) / 2)
      if (mid === midNext) {
        mid = 0
        break
      }
      mid = midNext
      let midT = entryEls[mid].offsetTop
      let midL = entryEls[mid].offsetLeft
      if (midT > targetT) {
        end = mid
      } else if (midT < targetT) {
        start = mid
      } else if (midL > targetL) {
        end = mid
      } else if (midL < targetL) {
        start = mid
      } else {
        break
      }
    }
    return mid
  }

  createRefactorElement (sentence, focusEntryEl) {
    return EntryRefactor.createRefactorElement(sentence, focusEntryEl)
  }

  refactorElementListenersDispenser (sentence) {
    return EntryRefactor.listenersDispenser(sentence)
  }

  confirmRefactorResult (refactorElement, replaceTargetEl) {
    let newInnerHtml = EntryRefactor.confirmRefactorResult(refactorElement)
    replaceTargetEl.innerHTML = newInnerHtml
  }

  onDestroy () {
    this.abandonSelected()
    super.onDestroy()
  }
}

export default EditModeEntry
